package sw.serial;

import sw.utils.Direction;
import sw.utils.JOCLUtils;

public class SW_Serial {
	private final int GAP = -1;
	private int match = 2;
	private int mismatch = -1;
	
	private int match(char a, char b) {
		return (a == b) ? match : mismatch;
	}
	
	// Find the maximum value for the current cell looking to the north, west and
	// north-west cells of the current cell.
	private void findMaximum(int[] matrix, int[] memory, int i, int j, char a, char b, int dim) {
	  int max = 0;

	  int mm = matrix[(j-1)+(i-1)*dim] + match(a, b);
	  if (mm > max) {
	    max = mm;
	    memory[j+i*dim] = Direction.NORTH_WEST.getCode();
	  }

	  int md = matrix[j+(i-1)*dim] + GAP;
	  if (md > max) {
	    max = md;
	    memory[j+i*dim] = Direction.NORTH.getCode();
	  }

	  int mi = matrix[(j-1)+i*dim] + GAP;
	  if (mi > max) {
	    max = mi;
	    memory[j+i*dim] = Direction.WEST.getCode();
	  }

	  if (max == 0) {
	    memory[j+i*dim] = Direction.CENTER.getCode();
	  }

	  matrix[j+i*dim] = max;
	}
	
	private void validateSubMatrix(int[] matrix, int[] memory, 
								   int i, int j,
								   String s1, String s2,
								   int sub, int dim) {
		int ii, jj;
		for (ii = i; ii < sub + i; ++ii) {
			int count = 0;
			for (jj = j; jj < sub + j; ++jj) {				
				findMaximum(matrix, memory, ii + 1, jj + 1, s1.charAt(jj), s2.charAt(ii), dim);
				count++;
			}
		}
	}
	
	private void sw(String s1, String s2, final int sub) {

		int m = s2.length(); // row
		int n = s1.length(); // column
		int dim = m + 1;
		int matrix[] = new int[dim * dim];
		int memory[] = new int[dim * dim];

		if (m % sub != 0 && n % sub != 0)
			return;

		int max = n / sub;

		int slice, j;
		for (slice = 0; slice < 2 * max - 1; ++slice) {
			int z = slice < max ? 0 : slice - max + 1;
			for (j = z; j <= slice - z; ++j) {
				validateSubMatrix(matrix, memory, j * sub, (slice - j) * sub,
						s1, s2, sub, dim);
			}
			
		}

		// swResult *result = traceback(s1, s2, memory, matrix);

//		printMatrix(matrix, dim);
//		System.out.println("done");
	}
	
	private void printMatrix(int[] matrix, int dim) {
		for (int i = 0; i < (dim*dim); i++) {			
			System.out.print(matrix[i] + " ");
			if ( (i+1) % dim == 0) {
				System.out.println("");
			}
		}
	}
	
	/**
	 *  args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s1 = JOCLUtils.generateSequenceStringWithLength(1000);
		String s2 = JOCLUtils.generateSequenceStringWithLength(1000);
		SW_Serial swSerial = new SW_Serial();
		long before = System.nanoTime();
		swSerial.sw(s1, s2, 1);
        long after = System.nanoTime();
        float totalDurationMs = (after-before)/1e6f;
        System.out.println("Total duration: "+totalDurationMs+"ms");
	}

}
